package cn.rengy.web.framework.security;

import java.nio.charset.StandardCharsets;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.http.Consts;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.shiro.util.AntPathMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.AsyncHandlerInterceptor;

import com.alibaba.fastjson.JSON;
import cn.rengy.lang.ResultEntity;
import cn.rengy.tool.web._WebUtils;
import cn.rengy.web.framework.role.service.SysAuthUriPO;
import cn.rengy.web.framework.role.service.SysAuthUriService;
import cn.rengy.web.framework.role.service.SysResourceUriPO;
import cn.rengy.web.framework.role.service.SysRoleRelService;
import cn.rengy.web.framework.util.GetSessionUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * 访问控制拦截器
 * 
 * 思路：
 * 保存系统所有的uri，筛选需要权限控制的uri
 * 角色对应权限，用户对应角色
 * 
 * 1. /** 这种ant匹配
 * 2. 具体到每个uri，不使用**匹配，只规定每个uri的权限
 * 3. 保存角色和对应的可访问uri
 * 4. 保存uri和对应可访问的角色，判断当前角色是否在uri的角色内存在
 */
@Slf4j
@Component
public class AccessControlInterceptor implements AsyncHandlerInterceptor {

	private AntPathMatcher pathMatcher = new AntPathMatcher();
	@Autowired
	private SysAuthUriService sysAuthUriService;
    
	@Autowired
	private SysRoleRelService sysRoleRelService;
	@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		boolean isAllow=false;//是否允许访问
		String uri=_WebUtils.getRequestURI(request);
		if(isUnifyUri(uri)){
        	//统一访问方式
			Long action_id=Long.parseLong(request.getParameter("action"));
			isAllow=checkUnifyUri(action_id,uri);
        }else {
        	isAllow=checkGeneralUri(uri);
        }
        //3.匹配
        if(!isAllow) {
        	response.setCharacterEncoding(Consts.UTF_8.name());
			response.setStatus(HttpStatus.FORBIDDEN.value());
	        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
	        //response.addHeader("Redirect-URL", loginUrl);
	        String str=JSON.toJSONString(ResultEntity.fail("无权访问"));
	        _WebUtils.responseWrite(str, response);
            return false;
        }
        return true;//允许访问
    }

    private boolean checkUnifyUri(Long action_id,String uri) {
    	boolean isAllow=false;//是否允许访问
    	//1.url是否需要授权访问呢
    	List<SysAuthUriPO> list=sysAuthUriService.getAll();
        boolean isAuth=false;
        if(list!=null){
        	for(SysAuthUriPO u:list){
        		String path=u.getUri();
        		if(isUnifyUri(path)) {
        			Long id=getActionid(path);
        			if(action_id.equals(id)) {
        				isAuth=true;
            			break;
        			}
        		}
        	}
        }
        if(!isAuth) {
        	return true;
        }
        //2.查询角色所有url
        Long userid=GetSessionUtils.getUserId();
        if(userid!=null){
        	List<SysAuthUriPO> allowUriList=sysRoleRelService.getUserAuthUri(userid);
        	if(allowUriList!=null){
        		for(SysAuthUriPO u:allowUriList) {
        			String path=u.getUri();
        			if(isUnifyUri(path)) {
            			Long id=getActionid(path);
            			if(action_id.equals(id)) {
            				isAuth=true;
                			break;
            			}
            		}
        		}
        	}
        }
    	return isAllow;
    }
    
    private boolean isUnifyUri(String path) {
    	return (pathMatcher.match("/authenticated/access/**", path)
        		||pathMatcher.match("/access/**", path));
    }
    private Long getActionid(String path) {
    	List<NameValuePair> nameList=URLEncodedUtils.parse(path, StandardCharsets.UTF_8);
    	for(NameValuePair nv:nameList) {
    		String name=nv.getName();
			String value=nv.getValue();
			if(name.equals("action_id")){
				return Long.parseLong(value);
			}
    	}
    	return null;
    }
    
    private boolean checkGeneralUri(String uri) {
    	boolean isAllow=false;//是否允许访问
    	//1.url是否需要授权访问呢
        List<SysAuthUriPO> list=sysAuthUriService.getAll();
        boolean isAuth=false;
        if(list!=null){
        	for(SysAuthUriPO u:list){
        		String path=u.getUri();
    			if(pathMatcher.match(path, uri)) {//需要授权才能访问
        			isAuth=true;
        			break;
        		}
        	}
        }
        if(!isAuth) {
        	return true;
        }
        //2.查询角色所有url
        Long userid=GetSessionUtils.getUserId();
        if(userid!=null){
        	List<SysAuthUriPO> allowUriList=sysRoleRelService.getUserAuthUri(userid);
        	if(allowUriList!=null) {
        		for(SysAuthUriPO u:allowUriList) {
        			String path=u.getUri();
            		if(pathMatcher.match(path, uri)) {//需要授权才能访问
            			isAllow=true;
            			break;
            		}
        		}
        	}
        }
        return isAllow;
    }
}
